package cn.yh.nft.turbo.auth.controller;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.yh.nft.turbo.api.notice.constant.NoticeConstant;
import cn.yh.nft.turbo.api.notice.response.NoticeResponse;
import cn.yh.nft.turbo.api.notice.service.NoticeFacadeService;
import cn.yh.nft.turbo.api.user.request.UserQueryRequest;
import cn.yh.nft.turbo.api.user.request.UserRegisterRequest;
import cn.yh.nft.turbo.api.user.response.UserOperatorResponse;
import cn.yh.nft.turbo.api.user.response.UserQueryResponse;
import cn.yh.nft.turbo.api.user.response.data.UserInfo;
import cn.yh.nft.turbo.api.user.service.UserFacadeService;
import cn.yh.nft.turbo.auth.exception.AuthException;
import cn.yh.nft.turbo.auth.param.LoginParam;
import cn.yh.nft.turbo.auth.param.RegistryParam;
import cn.yh.nft.turbo.auth.vo.LoginVO;
import cn.yh.nft.turbo.web.vo.Result;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import static cn.yh.nft.turbo.api.notice.constant.NoticeConstant.CAPTCHA_KEY_PREFIX;
import static cn.yh.nft.turbo.auth.exception.AuthErrorCode.VERIFICATION_CODE_WRONG;

/**
 * @ClassName: AuthController
 * @Author: 草莓爱上啵啵
 *
 *  认证相关接口
 */
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("auth")
public class AuthController {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @DubboReference(version = "1.0.0")
    private NoticeFacadeService noticeFacadeService;

    @DubboReference(version = "1.0.0")
    private UserFacadeService userFacadeService;

    /**
     * 默认登录超时时间为7天
     */
    private static final Integer DEFAULT_LOGIN_SESSION_TIMEOUT = 60 * 60 *24 *7;

    /**
     * 通过手机号发送验证码
     * @param telephone 验证码
     * @return
     */
    @GetMapping("/sendCaptcha")
    public Result<Boolean> sendCaptcha(@NotBlank String telephone){
        NoticeResponse noticeResponse = noticeFacadeService.generateAndSmsCaptcha(telephone);
        return Result.success(noticeResponse.getSuccess());
    }

    /**
     * 用户注册
     * @param registryParam 注册信息
     * @return
     */
    @PostMapping("/register")
    public Result<Boolean> register(@Valid @RequestBody RegistryParam registryParam){
        //验证码效验
        if (!parityCaptcha(registryParam.getTelephone(), registryParam.getCaptcha())) {
            //不正确直接返回异常信息
            throw new AuthException(VERIFICATION_CODE_WRONG);
        }
        //注册

        //注册结果返回
        UserOperatorResponse registerResponse = userRegister(registryParam.getTelephone(), registryParam.getInviteCode());
        if (registerResponse.getSuccess()) {
            return Result.success(true);
        }
        return Result.error(registerResponse.getResponseCode(), registerResponse.getResponseMessage());
    }


    /**
     * 登录方法
     * @param loginParam 登录信息
     * @return 结果
     */
    @PostMapping("/login")
    public Result<LoginVO> login(@Valid @RequestBody LoginParam loginParam){
        //验证码效验
        if (!parityCaptcha(loginParam.getTelephone(), loginParam.getCaptcha())){
            //不正确直接返回异常信息
            throw new AuthException(VERIFICATION_CODE_WRONG);
        }
        
        //创建一个用户请求参数
        UserQueryRequest userQueryRequest = new UserQueryRequest(loginParam.getTelephone());
        //调用用户服务查询用户信息
        UserQueryResponse<UserInfo> userQueryResponse = userFacadeService.query(userQueryRequest);
        //获取到用户对象
        UserInfo userInfo = userQueryResponse.getData();
        //判断是注册还是登录
        if (ObjectUtil.isEmpty(userInfo)){
            //注册
            UserOperatorResponse userOperatorResponse = userRegister(loginParam.getTelephone(), loginParam.getInviteCode());
            if (userOperatorResponse.getSuccess()) {
                //注册成功直接登录
                LoginVO login = login(userQueryRequest, userQueryResponse, userInfo, loginParam.getRememberMe());
                return Result.success(login);
            }
        } else {
            //登录
            //注册成功直接登录
            LoginVO login = login(userQueryRequest, userQueryResponse, userInfo, loginParam.getRememberMe());
            return Result.success(login);
        }
        //查询用户信息
        //登录
        //返回结果
        LoginVO loginVO = new LoginVO();
        return Result.success(loginVO);
    }

    /**
     * 退出登录
     * @return
     */
    @PostMapping("/logout")
    public Result<Boolean> logout(){

        //退出
        return Result.success(true);
    }

    /**
     * 用于用户注册方法
     * @param registryTelephone 注册手机号
     * @param inviteCode 邀请人邀请码
     * @return 注册成功返回true，失败返回false
     */
    private UserOperatorResponse userRegister(String registryTelephone, String inviteCode){
        UserRegisterRequest request = new UserRegisterRequest();
        request.setTelephone(registryTelephone);
        request.setInviteCode(inviteCode);

        return userFacadeService.register(request);
    }

    /**
     * 效验验证码
     * @param telephone 手机号
     * @param captcha 验证码
     * @return
     */
    private boolean parityCaptcha(String telephone, String captcha){
        //通过手机号取出redis中验证码
        //String redisCaptcha = redisTemplate.opsForValue().get(CAPTCHA_KEY_PREFIX + telephone);
        //为了测试方便，设置默认验证码
        String redisCaptcha = "8888";
        //调用equalsIgnoreCase方法进行比对验证码
        return StringUtils.equalsIgnoreCase(redisCaptcha, captcha);
    }

    /**
     * 一键登录方法
     * @param userQueryRequest
     * @param userInfo
     * @param rememberMe
     * @return
     */
    private LoginVO login(UserQueryRequest userQueryRequest, UserQueryResponse<UserInfo> userQueryResponse , UserInfo userInfo, Boolean rememberMe){
        //如果是注册的话，userInfo一定是空，重新查询信息并赋值
        if (ObjectUtil.isEmpty(userInfo)){
            //再查询一下用户信息
            userQueryResponse = userFacadeService.query(userQueryRequest);
            //将用户信息赋值给userInfo
            userInfo = userQueryResponse.getData();
        }

        //会话登录
        StpUtil.login(userInfo.getUserId(), new SaLoginModel()
                //是否为临时token
                .setIsLastingCookie(rememberMe)
                //指定token登录有效期限为7天
                .setTimeout(DEFAULT_LOGIN_SESSION_TIMEOUT));
        //获取当前已登录账号的 Account-Session，如果该 SaSession 尚未创建
        //并将用户id和用户信息以键值对的方式存入
        StpUtil.getSession().set(userInfo.getUserId().toString(), userInfo);
        //返回loginVo对象
        return new LoginVO(userInfo);
    }
}
